package com.jdd.modules.system.controller;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSONObject;
import com.google.code.kaptcha.Producer;
import com.jdd.common.api.vo.Result;
import com.jdd.common.aspect.annotation.LogLevelType;
import com.jdd.common.aspect.annotation.OperationLogDetail;
import com.jdd.common.aspect.annotation.OperationType;
import com.jdd.common.aspect.annotation.OperationUnit;
import com.jdd.common.constant.CommonConstant;
import com.jdd.common.system.api.ISysBaseAPI;
import com.jdd.common.system.util.JwtUtil;
import com.jdd.common.system.vo.LoginUser;
import com.jdd.common.util.PasswordUtil;
import com.jdd.common.util.RedisUtil;
import com.jdd.common.util.encryption.AesEncryptUtil;
import com.jdd.common.util.encryption.EncryptedString;
import com.jdd.common.util.encryption.RASUtil;
import com.jdd.common.util.oConvertUtils;
import com.jdd.modules.system.entity.SysUser;
import com.jdd.modules.system.model.SysLoginModel;
import com.jdd.modules.system.service.ISysLogService;
import com.jdd.modules.system.service.ISysUserDepartService;
import com.jdd.modules.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.*;

/**
 * 用户登录控制器
 * @author
 */
@RestController
@RequestMapping("/sys")
@Api(tags="用户登录")
@Slf4j
public class LoginController {
	@Autowired
	private ISysUserService sysUserService;
	@Autowired
	private ISysBaseAPI sysBaseAPI;
	@Autowired
	private ISysLogService logService;
	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private Producer producer;
	@Autowired
	private ISysUserDepartService sysUserDepartService;


	public final static String KAPTCHA_REDIS_KEY = "KAPTCHA_SESSION_KEY";

	@Value("${jdd.login.captcha:true}")
	private boolean isNeedCaptcha;
	/**  手机端许可登录 */
	public static int SIGNMOBILEPRIMISSION = 1;
	public static String ILLEGALUSER = "该用户非法！";
	public static String SIGNMOBILEFORBID = "用户无手持端权限！";
	public static String IDORPASSWORDERROR = "用户名或密码错误！";
	public static String USERNOTEXIST = "用户名不存在！";
	public static String USERBEFREEZEN = "用户已冻结！";
	public static String USERBELOGOFF = "用户名已注销！";
	public  static String ADMINSBEFORBIDDEN = "最高管理员权限的超管用户禁止登录手持端!";
	public  static String PARKINGNOTEXIST = "用户分配的车场不存在!";
	public  static String NOPARKINGAPPOINT = "用户未分配车场!";
	public  static String MOREPARKINGBEFOUND = "用户拥有多个车场!";
	public  static String NOPARKINCODEEXIST = "车场无编号!";

	public static int RESULT500 = 500;

	@RequestMapping(value = "/login", method = RequestMethod.POST)
	@ApiOperation("登录接口")
	@OperationLogDetail(detail ="登录",level= LogLevelType.ONE,operationType = OperationType.LOGIN,operationUnit = OperationUnit.USER)
	public Result<JSONObject> login(HttpServletRequest request, @RequestBody SysLoginModel sysLoginModel) throws Exception {
		Result<JSONObject> result;
		String username = sysLoginModel.getUsername();
		String oldpassword = sysLoginModel.getPassword().trim();
		String password = AesEncryptUtil.desEncrypt(URLDecoder.decode(oldpassword, CommonConstant.DEFAULT_CHARSET).replace(' ', '+'));

		if (StringUtils.isEmpty(password)) {
			password = oldpassword;
		}
		SysUser sysUser = sysUserService.getUserByName(username);
		String captchas = (String)redisUtil.get(sysLoginModel.getCaptcha());

		result = sysUserService.checkUserIsEffective(sysUser);
		if (RESULT500 == result.getCode()) {
			return result;
		}


		if (org.apache.commons.lang3.StringUtils.isBlank(captchas)){
			result.error500("验证码已失效");
			return result;
		}
		if (!sysLoginModel.getCaptcha().equals(captchas)){
			result.error500("验证码错误");
			return result;
		}

		// 校验用户是否有效
		if(!result.isSuccess()) {
			return result;
		}
		//校验数据的合法性
		if (StringUtils.isEmpty(sysUser.getSignature())) {
			result.error500("该用户非法");
			return result;
		}

		try{
			if(!RASUtil.verifySign(sysUser.getSignature(),sysUser.getUsername())) {
				result.error500("该用户非法");
				return result;
			}
		} catch (Exception e) {
			log.error("用户非法登录---> {}", e.getMessage());
			result.error500("该用户非法");
			return result;
		}

		//3. 校验用户名或密码是否正确
		String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
		String syspassword = sysUser.getPassword();

		if (!syspassword.equals(userpassword)) {
			result.error500("用户名或密码错误");
			return result;
		}

		//用户登录信息
		userInfo(sysUser, result);
		sysBaseAPI.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null);

 		return result;
	}

	/**
	 * 获取登录验证码
	 *
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping("/captcha")
	@ApiOperation("获取登录验证码")
	public Result<JSONObject> captcha(HttpServletRequest request, HttpServletResponse response,HttpSession session) throws IOException {
		JSONObject object = new JSONObject();
		response.setHeader("Cache-Control", "no-store, no-cache");
		response.setContentType("image/jpeg");


		//生成文字验证码
		String text = producer.createText();
		//生成图片验证码
		BufferedImage image = producer.createImage(text);

		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		//保存到 redis 设置过期时间
		redisUtil.set(text,text,120);
		ImageIO.write(image, "jpg", stream);
		String base64 = Base64.encode(stream.toByteArray());
		StringBuffer buffer = new StringBuffer();
		buffer.append("data:image/jpg;base64,");
		buffer.append(base64);
		object.put("text",text);
		object.put("image",buffer);
		return Result.ok(object);
	}

	/**
	 * 退出登录
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/logout")
	public Result<Object> logout(HttpServletRequest request,HttpServletResponse response) {
		//用户退出逻辑
		Subject subject = SecurityUtils.getSubject();
		LoginUser sysUser = (LoginUser)subject.getPrincipal();
		addLog("用户名: "+sysUser.getRealname()+",退出成功！");
		log.info(" 用户名:  "+sysUser.getRealname()+",退出成功！ ");
		subject.logout();
		//清空用户Token缓存
		redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + sysUser.getId());
		//清空用户权限缓存：权限Perms和角色集合
		redisUtil.del(CommonConstant.LOGIN_USER_CACHERULES_ROLE + sysUser.getUsername());
		redisUtil.del(CommonConstant.LOGIN_USER_CACHERULES_PERMISSION + sysUser.getUsername());
		return Result.ok("退出登录成功！");
	}

	/**
	 * 获取访问量
	 * @return
	 */
	@GetMapping("loginfo")
	public Result<JSONObject> loginfo() {
		Result<JSONObject> result = new Result<JSONObject>();
		JSONObject obj = new JSONObject();
		//update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
		// 获取一天的开始和结束时间
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		Date dayStart = calendar.getTime();
		calendar.add(Calendar.DATE, 1);
		Date dayEnd = calendar.getTime();
		// 获取系统访问记录
		Long totalVisitCount = logService.findTotalVisitCount();
		obj.put("totalVisitCount", totalVisitCount);
		Long todayVisitCount = logService.findTodayVisitCount(dayStart,dayEnd);
		obj.put("todayVisitCount", todayVisitCount);
		Long todayIp = logService.findTodayIp(dayStart,dayEnd);
		//update-end--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
		obj.put("todayIp", todayIp);
		result.setResult(obj);
		result.success("登录成功");
		return result;
	}

	/**
	 * 获取访问量
	 * @return
	 */
	@GetMapping("visitInfo")
	public Result<List<Map<String,Object>>> visitInfo() {
		Result<List<Map<String,Object>>> result = new Result<List<Map<String,Object>>>();
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.HOUR_OF_DAY,0);
		calendar.set(Calendar.MINUTE,0);
		calendar.set(Calendar.SECOND,0);
		calendar.set(Calendar.MILLISECOND,0);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		Date dayEnd = calendar.getTime();
		calendar.add(Calendar.DAY_OF_MONTH, -7);
		Date dayStart = calendar.getTime();
		List<Map<String,Object>> list = logService.findVisitCount(dayStart, dayEnd);
		result.setResult(oConvertUtils.toLowerCasePageList(list));
		return result;
	}


	/**
	 * 登陆成功选择用户当前部门
	 * @param user
	 * @return
	 */
	@RequestMapping(value = "/selectDepart", method = RequestMethod.PUT)
	public Result<?> selectDepart(@RequestBody SysUser user) {
		String username = user.getUsername();
		if(oConvertUtils.isEmpty(username)) {
			LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
			username = sysUser.getUsername();
		}
		String orgCode= user.getOrgCode();
		this.sysUserService.updateUserDepart(username, orgCode);
		return Result.ok();
	}

	/**
	 * 短信登录接口
	 *
	 * @param jsonObject
	 * @return
	 */
	@PostMapping(value = "/sms")
	public Result<String> sms(@RequestBody JSONObject jsonObject) {
		Result<String> result = new Result<String>();
		return result;
	}

/**
 * @Description:手机号登录接口
 * @author：  bin.wu@jdd.com
 * @Date:  2021/03/30
 * @version 1.0
 * @param jsonObject   JSONObject
 * @return Result<JSONObject>
 */
	@PostMapping("/phoneLogin")
	public Result<JSONObject> login(@RequestBody JSONObject jsonObject) {
		Result<JSONObject> result = new Result<JSONObject>();
		String phone = jsonObject.getString("mobile");

		//校验用户有效性
		SysUser sysUser = sysUserService.getUserByPhone(phone);
		result = sysUserService.checkUserIsEffective(sysUser);
		if(!result.isSuccess()) {
			return result;
		}

		String smscode = jsonObject.getString("captcha");
		Object code = redisUtil.get(phone);
		if (!smscode.equals(code)) {
			result.setMessage("手机验证码错误");
			return result;
		}
		//用户信息
		userInfo(sysUser, result);
		//添加日志
		addLog("用户名: " + sysUser.getUsername() + ",登录成功！");

		return result;
	}


	/**
	 * 用户信息
	 *
	 * @param sysUser
	 * @param result
	 * @return
	 */
	private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result) {
		String syspassword = sysUser.getPassword();
		String username = sysUser.getUsername();
		String userId = sysUser.getId();
		// 生成token
		String token = JwtUtil.sign(username, userId, syspassword);
//		if (redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + userId) != null) {
//
//		}
		redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + userId, token, JwtUtil.EXPIRE_TIME / 1000);


		// 获取用户部门信息
		JSONObject obj = new JSONObject();
		obj.put("token", token);
		obj.put("userInfo", sysUser);

//		result.setResult(getDeviceid(obj, userId));
		result.setResult(obj);
		result.success("登录成功");
		return result;
	}

	/**
	 * @Title: getDeviceid
	 * @Description:(获取用户绑定设备信息)
	 * @param obj
	 * @return
	 * @author: zjf
	 * @date 2021年8月19日
	 * @version 1.0
	 */
//	public JSONObject getDeviceid(JSONObject obj,String userId){
//		// 查询用户绑定设备
//		QueryWrapper<DeviceInfo> queryWrapper = new QueryWrapper<DeviceInfo>();
//		queryWrapper.eq("user_id", userId);
//		List<DeviceInfo> deviceInfoList = deviceInfoService.list(queryWrapper);
//		if(CollectionUtils.isNotEmpty(deviceInfoList)){
//			obj.put("deviceid", deviceInfoList.get(0).getDeviceCode());
//		}
//		return obj;
//	}

/**
 * @Description:用户信息
 * @author：  bin.wu@jdd.com
 * @Date:  2021/03/30
 * @version 1.0
 * @param sysUser 用户信息  SysUser
 * @param  result   Result<JSONObject>
 * @return Result<JSONObject>
 */
	private Result<JSONObject> userInfo4Mobile(SysUser sysUser, Result<JSONObject> result) {
		String syspassword = sysUser.getPassword();
		String username = sysUser.getUsername();
		String userId = sysUser.getId();
		// 生成token
		String token = JwtUtil.sign(username, userId, syspassword, JwtUtil.H5);
		redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + userId, token, (JwtUtil.MOBILE_LONGING_EXPIRE_TIME));

		// 获取用户部门信息
		JSONObject obj = new JSONObject();
		obj.put("token", token);
		result.setResult(obj);
		result.success("登录成功");
		return result;
	}

	/**
	 * 获取加密字符串
	 * @return
	 */
	@GetMapping(value = "/getEncryptedString")
	public Result<Map<String,String>> getEncryptedString(){
		Result<Map<String,String>> result = new Result<Map<String,String>>();
		Map<String,String> map = new HashMap<String,String>();
		map.put("key", EncryptedString.key);
		map.put("iv",EncryptedString.iv);
		result.setResult(map);
		return result;
	}

	void addLog(String logContent){
		sysBaseAPI.addLog(logContent,CommonConstant.LOG_TYPE_1,null);
	}

}
